/**
 * @file drv_uart.c
 * @author your name (you@domain.com)
 * @brief 串口设备驱动
 * @version 0.1
 * @date 2024-08-30
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#include <stdio.h>
#include <stdint.h>
#include <rtthread.h>
#include <rthw.h>
#include "n32g003.h"
#include "drv_uart.h"
#include "bsp_config.h"

struct uart_rx_fifo
{
    /* software fifo */
    uint8_t *buffer;

    uint16_t put_index, get_index;

    uint8_t is_full;
};

struct uart_configure
{
    uint32_t baud_rate; //波特率

    uint16_t data_bits; //数据位，直接填n32库中的定义
    uint16_t stop_bits; //停止位，直接填n32库中的定义 
    uint16_t parity;    //奇偶校验，直接填n23库中定义

    uint16_t bufsz;      //软件缓冲区大小
};

struct n32_uart
{
    void * uart_periph;   //uart 外设地址, UART10 UART1...
    void * tx_port;
    uint16_t tx_pin;
    void * rx_port;
    uint16_t rx_pin;
    uint8_t  tx_gpio_af;
    uint8_t  rx_gpio_af;
    struct uart_configure config;
    struct uart_rx_fifo * rxfifo;
};
#ifdef RT_USING_UART1
static uint8_t uart1_rx_buffer[UART1_RXBF_SIZE];
#endif
#ifdef RT_USING_UART2
static uint8_t uart2_rx_buffer[UART2_RXBF_SIZE];
#endif

#ifdef RT_USING_UART1
static struct uart_rx_fifo uart1_rxfifo = {uart1_rx_buffer,0,0,0};
#endif
#ifdef RT_USING_UART2
static struct uart_rx_fifo uart2_rxfifo = {uart2_rx_buffer,0,0,0};
#endif

#ifndef UART1_CONFIGURE
#define UART1_CONFIGURE     \
        {                   \
            115200,         \
            UART_WL_8B,    \
            UART_STPB_1,   \
            UART_PE_NO,    \
            UART1_RXBF_SIZE,\
        }
#endif
#ifndef UART2_CONFIGURE
#define UART2_CONFIGURE     \
        {                   \
            115200,         \
            UART_WL_8B,    \
            UART_STPB_1,   \
            UART_PE_NO,    \
            UART2_RXBF_SIZE,\
        }
#endif

static const struct n32_uart uarts[] = {
#ifdef RT_USING_UART1
    {
        UART1,
        UART1_TX_PORT,
        UART1_TX_PIN,
        UART1_RX_PORT,
        UART1_RX_PIN,
        UART1_TX_AF,
        UART1_RX_AF,       
        UART1_CONFIGURE,
        &uart1_rxfifo,
    },
#endif
#ifdef RT_USING_UART2
    {
        UART2,
        UART2_TX_PORT,
        UART2_TX_PIN,
        UART2_RX_PORT,
        UART2_RX_PIN,
        UART2_TX_AF,
        UART2_RX_AF,       
        UART2_CONFIGURE,
        &uart2_rxfifo,
    },
#endif
};

static void n32_uart_gpio_init(const struct n32_uart *uart)
{
    IRQn_Type irqn;
    GPIO_InitType GPIO_InitStructure;
    // NVIC_InitType NVIC_InitStructure;

    /* Initialize GPIO_InitStructure */
    GPIO_Structure_Initialize(&GPIO_InitStructure);
   
    /* Configure USART Tx as alternate function push-pull */
    GPIO_InitStructure.Pin            = uart->tx_pin;    
    GPIO_InitStructure.GPIO_Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStructure.GPIO_Alternate = uart->tx_gpio_af;
    GPIO_Peripheral_Initialize(uart->tx_port, &GPIO_InitStructure);

    /* Configure USART Rx as alternate function push-pull */
    GPIO_InitStructure.Pin            = uart->rx_pin;
    GPIO_InitStructure.GPIO_Alternate = uart->rx_gpio_af;
    GPIO_Peripheral_Initialize(uart->rx_port, &GPIO_InitStructure);

    /* NVIC config */
    if(uart->uart_periph == UART1)
        irqn = UART1_IRQn;
    else if(uart->uart_periph == UART2)    
        irqn = UART2_IRQn;

    NVIC_SetPriority(irqn, 0);
    NVIC_EnableIRQ(irqn);

    /* Enable the USARTy Interrupt */
    // NVIC_InitStructure.NVIC_IRQChannel                   = irqn;
    // NVIC_InitStructure.NVIC_IRQChannelPriority           = 0;
    // NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    // NVIC_Init(&NVIC_InitStructure);      
}

static void n32_enable_gpioclk(void *port, FunctionalState enable)
{
    /* Enable the GPIO Clock */
    if ((GPIO_Module*)port == GPIOA)
    {
        RCC_APB_Peripheral_Clock_Enable(RCC_APB_PERIPH_IOPA);
    }
    else if ((GPIO_Module*)port == GPIOB)
    {
        RCC_APB_Peripheral_Clock_Enable(RCC_APB_PERIPH_IOPA);
    }
}

static void n32_uart_rcc_init(const struct n32_uart *uart)
{
    /* Enable GPIO clock */
    n32_enable_gpioclk(uart->tx_port, ENABLE);
    n32_enable_gpioclk(uart->rx_port, ENABLE);
    
    /* Enable UART Clock */
    if(uart->uart_periph == UART1)
        RCC_APB_Peripheral_Clock_Enable(RCC_APB_PERIPH_UART1);
    else if(uart->uart_periph == UART2)
        RCC_APB_Peripheral_Clock_Enable(RCC_APB_PERIPH_UART2); 
}

static void n32_uart_config_init(const struct n32_uart *uart)
{
    UART_InitType UART_InitStructure;

    // UART_Reset(uart->uart_periph);
    /* UART configuration ------------------------------------------------------*/
    UART_InitStructure.BaudRate            = uart->config.baud_rate;
    UART_InitStructure.WordLength          = uart->config.data_bits;
    UART_InitStructure.StopBits            = uart->config.stop_bits;
    UART_InitStructure.Parity              = uart->config.parity;
    UART_InitStructure.Mode                = UART_MODE_RX | UART_MODE_TX;

    /* Configure USART */
    UART_Initializes(uart->uart_periph, &UART_InitStructure);

    /* Enable UART Receive interrupts */
    UART_Interrput_Enable(uart->uart_periph, UART_INT_RXDNE);

    /* Enable the USART */
    UART_Enable(uart->uart_periph);
}

static int n32_uart_putc(const struct n32_uart *uart, uint8_t ch)
{

    /* Send one byte to USART */
    UART_Data_Send(uart->uart_periph, ch);
    /* Loop until UARTz DAT register is empty */
    while (UART_Flag_Status_Get(uart->uart_periph, UART_FLAG_TXDE) == RESET);
    return 1;
}

static int n32_uart_getc(const struct n32_uart *uart)
{
    int ch = -1;

    /* check UART Receive Data Register is not empty */
    if (UART_Flag_Status_Get(uart->uart_periph, UART_FLAG_RXDNE) != RESET)      
        ch = UART_Data_Receive(uart->uart_periph);
    return ch;
}

/**
 * @brief 串口接收数据中断处理程序
 * 
 * @param uart 
 */
static void drv_uart_rxind(const struct n32_uart *uart)
{
    int ch = -1;
    rt_base_t level;
    struct uart_rx_fifo* rx_fifo;

    /* interrupt mode receive */
    rx_fifo = uart->rxfifo;
    RT_ASSERT(rx_fifo != RT_NULL);         

    while (1)
    {
        ch = n32_uart_getc(uart);
        if (ch == -1) break;


        /* disable interrupt */
        level = rt_hw_interrupt_disable();

        rx_fifo->buffer[rx_fifo->put_index] = ch;
        rx_fifo->put_index += 1;
        if (rx_fifo->put_index >= uart->config.bufsz) rx_fifo->put_index = 0;

        /* if the next position is read index, discard this 'read char' */
        if (rx_fifo->put_index == rx_fifo->get_index)
        {
            rx_fifo->get_index += 1;
            rx_fifo->is_full = RT_TRUE;
            if (rx_fifo->get_index >= uart->config.bufsz) rx_fifo->get_index = 0;
        }

        /* enable interrupt */
        rt_hw_interrupt_enable(level);
    }
}

static void n32_usart_isr(const struct n32_uart *uart)
{
    /* UART in mode Receiver */
    if (UART_Flag_Status_Get(uart->uart_periph, UART_INT_RXDNE) != RESET)
    {
        drv_uart_rxind(uart);
    }
	// if(USART_GetFlagStatus(uart->uart_periph, USART_FLAG_IDLEF | USART_FLAG_OREF | USART_FLAG_NEF | USART_FLAG_FEF | USART_FLAG_PEF) != RESET)
	// {
	// 	USART_ReceiveData(uart->uart_periph);		
	// }
}

/**
 * @brief lpuart 和 usart 硬件中断服务程序
 * 
 */

#ifdef RT_USING_UART1
void UART1_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    n32_usart_isr(&uarts[0]);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif

#ifdef RT_USING_UART2
void UART2_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
#if defined(RT_USING_UART1)
    n32_usart_isr(&uarts[1]);
#else
    n32_usart_isr(&uarts[0]);
#endif
/* leave interrupt */
    rt_interrupt_leave();
}
#endif
/**
 * @brief 初始化串口设备
 * 
 */
int n32_uart_init(void) 
{
    int i;
    for (i = 0; i < sizeof(uarts) / sizeof(uarts[0]); i++)
    {
        /* RCC config */
        n32_uart_rcc_init(&uarts[i]);
        /* GPIO and NVIC config */
        n32_uart_gpio_init(&uarts[i]);
        /* N32 uart config */
        n32_uart_config_init(&uarts[i]);
    }
    return i;
}

/**
 * @brief 从串口读取数据
 * @param uartx 串口设备号，UartDevice
 * @param buffer 数据读取缓冲区
 * @param length 指定读取长度
 * @return int >=0, 读取到的数据长度，<0, 错误码
 * 
 * 该函数将从指定设备号的设备缓冲区读取指定长度的数据，读取后将立即返回
 */
int uart_read(UartDevice uartx, void *buffer, unsigned int length)
{
    const struct n32_uart *uart;
    struct uart_rx_fifo *rx_fifo;
    int size;
    uint8_t *data = (uint8_t *)buffer;

    if(uartx >= sizeof(uarts) / sizeof(uarts[0])) return -RT_ERROR;

    uart = &uarts[uartx];
    size = length;

    rx_fifo = uart->rxfifo;
    RT_ASSERT(rx_fifo != RT_NULL);

    /* read from software FIFO */
    while (length)
    {
        int ch;
        rt_base_t level;

        /* disable interrupt */
        level = rt_hw_interrupt_disable();

        /* there's no data: */
        if ((rx_fifo->get_index == rx_fifo->put_index) && (rx_fifo->is_full == RT_FALSE))
        {
            /* no data, enable interrupt and break out */
            rt_hw_interrupt_enable(level);
            break;
        }

        /* otherwise there's the data: */
        ch = rx_fifo->buffer[rx_fifo->get_index];
        rx_fifo->get_index += 1;
        if (rx_fifo->get_index >= uart->config.bufsz) rx_fifo->get_index = 0;

        if (rx_fifo->is_full == RT_TRUE)
        {
            rx_fifo->is_full = RT_FALSE;
        }

        /* enable interrupt */
        rt_hw_interrupt_enable(level);

        *data = ch & 0xff;
        data ++; length --;
    }

    return size - length;
}

/**
 * @brief 写数据到串口
 * 
 * @param uartx 串口设备号，UartDevice
 * @param buffer 数据输出缓冲区
 * @param length 数据长度
 * @return int 实际写入的数据长度
 */
int uart_write(UartDevice uartx, const void *buffer, unsigned int length)
{
    const uint8_t *data = buffer;
    if(uartx >= sizeof(uarts) / sizeof(uarts[0])) return -RT_ERROR;

    while(length --)
    {
        n32_uart_putc(&uarts[uartx], *data);
        data ++;
    }

    return data - (uint8_t *)buffer;
}

INIT_BOARD_EXPORT(n32_uart_init);
